/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef GrMtlPipelineState_DEFINED
#define GrMtlPipelineState_DEFINED

#include "include/private/gpu/ganesh/GrTypesPriv.h"
#include "src/gpu/ganesh/GrStencilSettings.h"
#include "src/gpu/ganesh/glsl/GrGLSLProgramBuilder.h"
#include "src/gpu/ganesh/mtl/GrMtlBuffer.h"
#include "src/gpu/ganesh/mtl/GrMtlPipeline.h"
#include "src/gpu/ganesh/mtl/GrMtlPipelineStateDataManager.h"

#import <Metal/Metal.h>

class GrMtlFramebuffer;
class GrMtlGpu;
class GrMtlPipelineStateDataManager;
class GrMtlRenderCommandEncoder;
class GrMtlRenderPipeline;
class GrMtlSampler;
class GrMtlTexture;
class GrPipeline;

/* *
 * Wraps a MTLRenderPipelineState object and also contains more info about the pipeline as needed
 * by Ganesh
 */
class GrMtlPipelineState {
public:
    using UniformInfoArray = GrMtlPipelineStateDataManager::UniformInfoArray;
    using UniformHandle = GrGLSLProgramDataManager::UniformHandle;

    GrMtlPipelineState(GrMtlGpu *, sk_sp<GrMtlRenderPipeline> pipeline, MTLPixelFormat,
        const GrGLSLBuiltinUniformHandles &builtinUniformHandles, const UniformInfoArray &uniforms,
        uint32_t uniformBufferSize, uint32_t numSamplers, std::unique_ptr<GrGeometryProcessor::ProgramImpl>,
        std::unique_ptr<GrXferProcessor::ProgramImpl>,
        std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fpImpls);

    const sk_sp<GrMtlRenderPipeline> &pipeline() const
    {
        return fPipeline;
    }

    void setData(GrMtlFramebuffer *, const GrProgramInfo &);

    void setTextures(const GrGeometryProcessor &, const GrPipeline &, const GrSurfaceProxy * const geomProcTextures[]);
    void bindTextures(GrMtlRenderCommandEncoder *renderCmdEncoder);

    void setDrawState(GrMtlRenderCommandEncoder *, const skgpu::Swizzle &writeSwizzle, const GrXferProcessor &);

    static void SetDynamicScissorRectState(GrMtlRenderCommandEncoder *renderCmdEncoder,
        SkISize colorAttachmentDimensions, GrSurfaceOrigin rtOrigin, SkIRect scissorRect);

    bool doesntSampleAttachment(const MTLRenderPassAttachmentDescriptor *) const;

private:
    /* *
     * We use the RT's size and origin to adjust from Skia device space to Metal normalized device
     * space and to make device space positions have the correct origin for processors that require
     * them.
     */
    struct RenderTargetState {
        SkISize fRenderTargetSize;
        GrSurfaceOrigin fRenderTargetOrigin;

        RenderTargetState()
        {
            this->invalidate();
        }
        void invalidate()
        {
            fRenderTargetSize.fWidth = -1;
            fRenderTargetSize.fHeight = -1;
            fRenderTargetOrigin = (GrSurfaceOrigin)-1;
        }
    };

    void setRenderTargetState(SkISize colorAttachmentDimensions, GrSurfaceOrigin);

    void bindUniforms(GrMtlRenderCommandEncoder *);

    void setBlendConstants(GrMtlRenderCommandEncoder *, const skgpu::Swizzle &, const GrXferProcessor &);

    void setDepthStencilState(GrMtlRenderCommandEncoder *renderCmdEncoder);

    struct SamplerBindings {
        GrMtlSampler *fSampler;
        id<MTLTexture> fTexture;

        SamplerBindings(GrSamplerState state, GrTexture *texture, GrMtlGpu *);
    };

    GrMtlGpu *fGpu;
    sk_sp<GrMtlRenderPipeline> fPipeline;
    MTLPixelFormat fPixelFormat;

    RenderTargetState fRenderTargetState;
    GrGLSLBuiltinUniformHandles fBuiltinUniformHandles;

    GrStencilSettings fStencil;

    int fNumSamplers;
    skia_private::TArray<SamplerBindings> fSamplerBindings;

    std::unique_ptr<GrGeometryProcessor::ProgramImpl> fGPImpl;
    std::unique_ptr<GrXferProcessor::ProgramImpl> fXPImpl;
    std::vector<std::unique_ptr<GrFragmentProcessor::ProgramImpl>> fFPImpls;

    GrMtlPipelineStateDataManager fDataManager;
};

#endif
